@model WalletSendModel

<div class="form-group hide-when-js">
    <label asp-for="SelectedInputs" class="form-label"></label>
    <select multiple="multiple" asp-for="SelectedInputs" class="form-select">
        @foreach (var input in Model.InputsAvailable)
        {
            <option value="@input.Outpoint" class="text-truncate" asp-selected="@(Model.SelectedInputs?.Contains(input.Outpoint)??false)">(@input.Amount) @input.Outpoint</option>
        }
    </select>
</div>
<style>
    #coin-selection-app .btn-link { --btcpay-btn-color: var(--btcpay-body-text-muted); }
    #coin-selection-app .btn-link:hover { --btcpay-btn-color: var(--btcpay-body-link-accent); }
    #coin-selection-app .btn-link.active { --btcpay-btn-active-color: var(--btcpay-body-link); }
</style>
<div id="coin-selection-app" class="only-for-js" v-cloak>
    <div class="d-sm-flex justify-content-between align-items-center">
        <h5 class="mb-sm-0" text-translate="true">Coin selection</h5>
        <span class="text-muted text-end">
            <span>@StringLocalizer["{0} selected", "{{selectedItems.length}}"]</span>
            <span v-show="selectedItems.length > 0">({{selectedAmount}} @Model.CryptoCode)</span>
            <span>/ @StringLocalizer["{0} total", "{{items.length}}"] (@Model.CurrentBalance&nbsp;@Model.CryptoCode)</span>
        </span>
    </div>
    <input type="text" v-model="filter" class="form-control my-3" placeholder="@StringLocalizer["Filter by transaction id, amount, label, comment"]"/>
    <details class="text-muted small mt-2">
        <summary text-translate="true">Available Filters (click to expand)</summary>
        <ul class="mb-0">
            <li class="mb-2"><b text-translate="true">General text search:</b> <span text-translate="true">txid, amount, comment, label</span></li>
            <li class="mb-2">
                <b text-translate="true">Minimum amount:</b>
                <code class="clipboard-button clipboard-button-hover" :data-clipboard="'amountmin:'">amountmin:0.001</code>
            </li>
            <li class="mb-2">
                <b text-translate="true">Maximum amount:</b>
                <code class="clipboard-button clipboard-button-hover" :data-clipboard="'amountmax:'">amountmax:0.01</code>
            </li>
            <li class="mb-2">
                <b text-translate="true">Created before date:</b>
                <code class="clipboard-button clipboard-button-hover" :data-clipboard="'before:'">before:2024-01-01</code>
            </li>
            <li class="mb-2">
                <b text-translate="true">Created after date:</b>
                <code class="clipboard-button clipboard-button-hover" :data-clipboard="'after:'">after:2023-01-01</code>
            </li>
            <li class="mb-2"><b text-translate="true">Combine filters:</b> <code>tag1 amountmin:0.0005 before:2024-01-01</code></li>
        </ul>
    </details>
    <div class="d-flex justify-content-between align-items-center my-2">
        <div class="d-flex gap-2 align-items-center">
            <input class="form-check-input flex-shrink-0"
                   id="select-all-checkbox"
                   type="checkbox"
                   :checked="isSelectAllChecked"
                   v-on:change="toggleSelectAllItems" />
            <span text-translate="true">Select All</span>
        </div>

        <div class="d-flex gap-2 align-items-center">
            <span text-translate="true">Sort by</span>
            <div class="btn-group gap-3" role="group">
                <button type="button" class="btn btn-link p-0"
                        :class="{active: sortOrder.startsWith('amount')}"
                        v-on:click="sortBy('amount')" text-translate="true">Amount</button>
                <button type="button" class="btn btn-link p-0"
                        :class="{active: sortOrder.startsWith('confs')}"
                        v-on:click="sortBy('confs')" text-translate="true">Confirmations</button>
            </div>
        </div>
    </div>
    <ul class="list-group list-group-flush mb-3" v-show="filteredItems.length">
        <li class="list-group-item py-2 cursor-pointer gap-2 align-items-center justify-content-between"
            v-for="item of filteredItems"
            :key="item.outpoint"
            :class="{ 'active': item.selected }"
            v-on:click="toggleItem($event, item, !item.selected)">
            <div class="d-flex align-items-start flex-grow-1 gap-2" style="min-width:0">
                <input class="form-check-input flex-shrink-0"
                       type="checkbox"
                       :id="item.outpoint"
                       :value="item.outpoint"
                       :checked="item.selected">
                <a :href="item.link" target="_blank" class="text-truncate flex-grow-1" v-tooltip="item.outpoint">{{item.outpoint}}</a>
                <div v-if="item.labels" class="d-flex flex-wrap gap-2 flex-fill" style="min-width:20%;max-width:40%;">
                    <span v-for="label of item.labels"
                       key="label.text"
                       class="transaction-label"
                       data-bs-toggle="tooltip"
                       v-tooltip="label.tooltip"
                       :style="styles(label.color)">
                        {{label.text}}
                    </span>
                </div>
                <span v-if="item.comment" data-bs-toggle="tooltip" v-tooltip="item.comment" class="badge bg-info rounded-pill" style="min-width:2em">
                    <vc:icon symbol="info" />
                </span>
                <span :class="{'bg-secondary' : item.confirmations > 0, 'bg-warning' : item.confirmations <= 0}"
                      class="badge d-inline-flex align-items-center gap-1 py-1"
                      data-bs-toggle="tooltip"
                      v-tooltip="`${item.confirmations} confirmation${item.confirmations === 1 ? '' : 's'}`">
                    {{item.confirmations}} <vc:icon symbol="block" />
                </span>
                <span class="text-nowrap flex-shrink-0 ms-2" style="font-family: 'Courier';">{{item.amount.toFixed(@Model.CryptoDivisibility)}} @Model.CryptoCode</span>
            </div>
        </li>
    </ul>

    <div class="d-grid d-sm-flex flex-wrap gap-3 justify-content-between">
        <ul class="pagination">
            <li class="page-item" :class="{'disabled' : pageStart == 0}">
                <a class="page-link p-0" tabindex="-1" href="#" v-on:click.prevent="page = page -1">«</a>
            </li>
            <li class="page-item disabled">
                <span class="page-link p-0">@StringLocalizer["Showing {0} of {1}", "{{pageStart+1}}-{{pageEnd}}", "{{currentItems.length}}"]</span>
            </li>
            <li class="page-item" :class="{'disabled' : pageEnd>= currentItems.length}">
                <a class="page-link p-0" href="#" v-on:click.prevent="page = page +1">»</a>
            </li>
        </ul>
        <div class="btn-group gap-3">
            <button type="button" :disabled="selectedInputs.length === 0" v-on:click="showSelectedOnly = !showSelectedOnly; page = 0" class="btn btn-link p-0">
                <template text-translate="true" v-if="showSelectedOnly">Show all</template>
                <template text-translate="true" v-else>Show selected only</template>
            </button>
            <button type="button" :disabled="showSelectedOnly" v-on:click="showUnconfirmedOnly = !showUnconfirmedOnly; page = 0" class="btn btn-link p-0" v-if="hasUnconfirmed">
                <template text-translate="true" v-if="showUnconfirmedOnly">Show unconfirmed coins</template>
                <template text-translate="true" v-else>Hide unconfirmed coins</template>
            </button>
        </div>
        <div class="d-flex gap-2 align-items-center">
            <span class="text-muted" text-translate="true">Page Size:</span>
            <div class="btn-group gap-2" role="group">
                <button type="button" class="btn btn-link p-0" :class="{active: pageSize === 10}" v-on:click="pageSize = 10; page = 0">10</button>
                <button type="button" class="btn btn-link p-0" :class="{active: pageSize === 25}" v-on:click="pageSize = 25; page = 0">25</button>
                <button type="button" class="btn btn-link p-0" :class="{active: pageSize === 50}" v-on:click="pageSize = 50; page = 0">50</button>
                <button type="button" class="btn btn-link p-0" :class="{active: pageSize === 100}" v-on:click="pageSize = 100; page = 0">100</button>
                <button type="button" class="btn btn-link p-0" :class="{active: pageSize === 250}" v-on:click="pageSize = 250; page = 0">250</button>
                <button type="button" class="btn btn-link p-0" :class="{active: pageSize === 500}" v-on:click="pageSize = 500; page = 0">500</button>
            </div>
        </div>
    </div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
    Vue.directive('tooltip', function(el, binding) {
        new bootstrap.Tooltip(el, {
            title: binding.value,
            placement: binding.arg || "auto",
            trigger: 'hover'
        });
    });

    function roundNumber(number, decimals) {
        var newnumber = new Number(number + '').toFixed(parseInt(decimals));
        return parseFloat(newnumber);
    }

    new Vue({
        el: '#coin-selection-app',
        data: {
            filter: "",
            items: @Safe.Json(Model.InputsAvailable),
            selectedInputs: $("#SelectedInputs").val(),
            page: 0,
            pageSize: 10,
            showSelectedOnly: false,
            showUnconfirmedOnly: false,
            sortOrder: 'amount-desc'
        },
        watch: {
            filter: function() {
                this.page = 0;
                this.handle();
            },
            showSelectedOnly: function() {
                this.handle();
            },
            selectedInputs: function() {
                this.handle();
            },
            showUnconfirmedOnly: function() {
                this.handle();
            }
        },
        computed: {
            currentItems: function() {
                const items = this.showSelectedOnly ? this.selectedItems : this.items.filter(i=> (!this.showUnconfirmedOnly || i.confirmations ));
                return this.sorted(items);
            },
            pageStart: function() {
                return this.page === 0 ? 0 : this.page * this.pageSize;
            },
            pageEnd: function() {
                var result = this.pageStart + this.pageSize;
                if (result > this.currentItems.length) {
                    result = this.currentItems.length;
                }
                return result;
            },
            hasUnconfirmed: function() {
                return this.items.filter(i => !i.confirmations).length > 0;
            },
            filteredItems: function () {
                const searchInput = this.filter.trim();
                const parsedFilters = {};
                const filteredResults = [];

                if (searchInput) {
                    for (const part of searchInput.split(" ")) {
                        const [key, value] = part.split(":");
                        if (value !== undefined) {
                            parsedFilters[key.toLowerCase()] = value;
                        } else {
                            parsedFilters.text = parsedFilters.text ? parsedFilters.text + " " + key : key;
                        }
                    }
                }

                const amountMin = parsedFilters.amountmin ? parseFloat(parsedFilters.amountmin) : null;
                const amountMax = parsedFilters.amountmax ? parseFloat(parsedFilters.amountmax) : null;
                const beforeDate = parsedFilters.before ? new Date(parsedFilters.before).getTime() : null;
                const afterDate = parsedFilters.after ? new Date(parsedFilters.after).getTime()  : null;
                const searchTerm = parsedFilters.text?.toLowerCase();

                for (const utxo of this.currentItems) {
                    const matchesText = !searchTerm || (
                        utxo.outpoint.toLowerCase().includes(searchTerm) ||
                        utxo.amount.toString().includes(searchTerm) ||
                        (utxo.comment?.toLowerCase().includes(searchTerm)) ||
                        (utxo.labels?.some(l => l.text.toLowerCase().includes(searchTerm) || l.tooltip.toLowerCase().includes(searchTerm)))
                    );

                    if (!matchesText) continue;
                    if (amountMin !== null && utxo.amount < amountMin) continue;
                    if (amountMax !== null && utxo.amount > amountMax) continue;

                    if (beforeDate !== null && utxo.timestamp) {
                        const utxoTime = new Date(utxo.timestamp).getTime();
                        if (utxoTime >= beforeDate) continue;
                    }

                    if (afterDate !== null && utxo.timestamp) {
                        const utxoTime = new Date(utxo.timestamp).getTime();
                        if (utxoTime <= afterDate) continue;
                    }

                    filteredResults.push({
                        ...utxo,
                        selected: this.selectedInputs.includes(utxo.outpoint)
                    });
                }
                return filteredResults.slice(this.pageStart, this.pageEnd);
            },
            selectedItems: function() {
                var result = [];
                for (var i = 0; i < this.items.length; i++) {
                    var currentItem = this.items[i];

                    if (this.selectedInputs.indexOf(currentItem.outpoint) != -1) {
                        result.push(currentItem);
                    }
                }
                return result;
            },
            selectedAmount: function() {
                var result = 0;
                for (let i = 0; i < this.selectedItems.length; i++) {
                    result += this.selectedItems[i].amount;
                }
                return roundNumber(result, 12);
            },
            isSelectAllChecked: function () {
                const visibleOutpoints = this.filteredItems.map(i => i.outpoint);
                return visibleOutpoints.length > 0 && visibleOutpoints.every(outpoint => this.selectedInputs.includes(outpoint));
            }
        },
        mounted: function() {
            var self = this;
            self.selectedInputs = $("#SelectedInputs").val();
            $(".crypto-balance-link").text(this.selectedAmount);
            $("#SelectedInputs").on("input change", function() {
                self.selectedInputs = $("#SelectedInputs").val();
            });
        },
        methods: {
            sorted: function(items) {
                switch (this.sortOrder) {
                    case 'amount-desc': return items.sort((a, b) => b.amount - a.amount)
                    case 'amount-asc': return items.sort((a, b) => a.amount - b.amount)
                    case 'confs-desc': return items.sort((a, b) => b.confirmations - a.confirmations)
                    case 'confs-asc': return items.sort((a, b) => a.confirmations - b.confirmations)
                    default: return items;
                }
            },
            sortBy: function(type) {
                this.sortOrder = this.sortOrder === `${type}-desc` ? `${type}-asc` : `${type}-desc`
                // reset page
                this.page = 0;
            },
            handle: function() {
                if (this.selectedInputs.length === 0) {
                    this.showSelectedOnly = false;
                }
                if (this.currentItems.length < this.pageEnd) {
                    this.page = 0;
                }
            },
            toggleItem: function(evt, item, toggle) {
                if (evt.target.tagName === "A") {
                    return;
                }

                let res = $("#SelectedInputs").val() || [];

                if (toggle) {
                    res.push(item.outpoint);
                } else {
                    res = res.filter(i => i !== item.outpoint);
                }

                // Do NOT use $("select option") or you'll break other selects like output labels
                $("select[name='SelectedInputs'] option").each(function () {
                    var selected = res.indexOf($(this).attr("value")) !== -1;
                    $(this).attr("selected", selected ? "selected" : null);
                });

                this.selectedInputs = res;
                $(".crypto-balance-link").text(this.selectedAmount);
            },
            toggleSelectAllItems: function () {
                const filteredOutpoints = this.filteredItems.map(item => item.outpoint);
                let res = $("#SelectedInputs").val() || [];

                const allSelected = filteredOutpoints.every(outpoint => res.includes(outpoint));

                if (allSelected) {
                    res = res.filter(outpoint => !filteredOutpoints.includes(outpoint));
                } else {
                    const set = new Set(res);
                    filteredOutpoints.forEach(outpoint => set.add(outpoint));
                    res = Array.from(set);
                }

                $("#SelectedInputs").find("option").each(function () {
                    var selected = res.indexOf($(this).attr("value")) !== -1;
                    $(this).attr("selected", selected ? "selected" : null);
                });

                this.selectedInputs = res;
                $(".crypto-balance-link").text(this.selectedAmount);
            },
            styles: function (bgColor) {
                let color = 'inherit'
                if (bgColor.slice(0, 1) === '#') {
                    const hex = bgColor.slice(1);
                    // Convert to RGB value
                    const r = parseInt(hex.substr(0,2), 16);
                    const g = parseInt(hex.substr(2,2), 16);
                    const b = parseInt(hex.substr(4,2), 16);
                    // Get YIQ ratio
                    const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
                    // Check contrast
                    color = (yiq >= 128) ? 'black' : 'white';
                }
                return { '--label-bg': bgColor, '--label-fg': color }
            }
        }
    });
});
</script>

<script src="~/js/copy-to-clipboard.js" asp-append-version="true"></script>
